﻿using System;
using System.Collections;
using System.IO;
using System.IO.IsolatedStorage;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections.Generic;

namespace HurlBat.XEdit2D
{
    [Serializable]
    public class ApplicationStorage:Hashtable
    {
        const string _FrameWidthKey = "FrameWidth";
        const string _FrameHeightKey = "FrameHeight";
        const string _FramesPerRowKey = "FramesPerRow";
        const string _FramesPerColumnKey = "FramesPerColumn";
        const string _TotalFramesKey = "TotalFrames";
        const string _RemoveImagesKey = "RemoveImages";
        const string _ContentFolderKey = "ContentFolder";
        const string _CharacterActionsKey = "CharacterActions";
        const string _CharacterTypeKey = "CharacterType";
        const string _RemoveAnimationsKey = "RemoveAnimations";

        /// <summary>
        /// The width of a frame
        /// </summary>
        public decimal FrameWidth
        {
            get { return GetDecimalValue(_FrameWidthKey); }
            set { SetValue<decimal>(_FrameWidthKey, value); }
        }
        /// <summary>
        /// The height of a frame
        /// </summary>
        public decimal FrameHeight
        {
            get { return GetDecimalValue(_FrameHeightKey); }
            set { SetValue<decimal>(_FrameHeightKey, value); }
        }
        /// <summary>
        /// The number of frames per row in an image
        /// </summary>
        public decimal FramesPerRow
        {
            get { return GetDecimalValue(_FramesPerRowKey); }
            set { SetValue<decimal>(_FramesPerRowKey, value); }
        }
        /// <summary>
        /// The number of frames per column in an image
        /// </summary>
        public decimal FramesPerColumn
        {
            get { return GetDecimalValue(_FramesPerColumnKey); }
            set { SetValue<decimal>(_FramesPerColumnKey, value); }
        }
        /// <summary>
        /// The total number of frames in an image (ignored if 0)
        /// </summary>
        public decimal TotalFrames
        {
            get { return GetDecimalValue(_TotalFramesKey); }
            set { SetValue<decimal>(_TotalFramesKey, value); }
        }
        /// <summary>
        /// If true, selected images will be removed from the list after creating the animation(s)
        /// </summary>
        public bool RemoveImages
        {
            get { return GetBoolValue(_RemoveImagesKey); }
            set { SetValue<bool>(_RemoveImagesKey, value); }
        }
        /// <summary>
        /// The content folder of the project
        /// </summary>
        public string ContentFolder
        {
            get { return GetStringValue(_ContentFolderKey); }
            set { SetValue<string>(_ContentFolderKey, value); }
        }
        /// <summary>
        /// The list of possible actions for the character
        /// </summary>
        public string[] CharacterActions
        {
            get { return GetStringArrayValue(_CharacterActionsKey); }
            set { SetValue<string[]>(_CharacterActionsKey, value); }
        }
        /// <summary>
        /// The type of the character. Will decide upon possible directions of animation
        /// </summary>
        public string CharacterType
        {
            get { return GetStringValue(_CharacterTypeKey); }
            set { SetValue<string>(_CharacterTypeKey, value); }
        }
        /// <summary>
        /// If true, selected animations will be removed from the list after creating the character
        /// </summary>
        public bool RemoveAnimations
        {
            get { return GetBoolValue(_RemoveAnimationsKey); }
            set { SetValue<bool>(_RemoveAnimationsKey, value); }
        }

        // File name. Let us use the entry assembly name with .dat as the extension.
        private string settingsFileName =
                        System.Reflection.Assembly.GetEntryAssembly().GetName().Name + ".dat";

        // The default constructor.
        public ApplicationStorage()
        {
            Load();
        }

        #region Getters and Setters for specific types
        string GetStringValue(string key)
        {
            return GetStringValue(key, string.Empty);
        }
        string GetStringValue(string key, string defValue)
        {
            if (!this.ContainsKey(key)) return defValue;
            return this[key] as string;
        }
        string[] GetStringArrayValue(string key)
        {
            return GetStringArrayValue(key, new string[] { });
        }
        string[] GetStringArrayValue(string key, string[] defValue)
        {
            if (!this.ContainsKey(key)) return defValue;
            return this[key] as string[];
        }
        decimal GetDecimalValue(string key)
        {
            return GetDecimalValue(key, 0);
        }
        decimal GetDecimalValue(string key, decimal defValue)
        {
            if (!this.ContainsKey(key)) return defValue;
            if (this[key] == null) return defValue;
            try
            {
                return Decimal.Parse(this[key].ToString());
            }
            catch (Exception)
            {
                return defValue;
            }
        }
        bool GetBoolValue(string key)
        {
            return GetBoolValue(key, false);
        }
        bool GetBoolValue(string key, bool defValue)
        {
            if (!this.ContainsKey(key)) return defValue;
            if (this[key] == null) return defValue;
            try
            {
                return Boolean.Parse(this[key].ToString());
            }
            catch (Exception)
            {
                return defValue;
            }
        }
        void SetValue<T>(string key, T value)
        {
            if (!this.ContainsKey(key)) this.Add(key, value);
            else this[key] = value;
        }
        #endregion

        // This constructor is required for deserializing our class from persistent storage.
        protected ApplicationStorage(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }

        private void Load()
        {
            IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User
                        | IsolatedStorageScope.Assembly, null, null);
            if (isoStore.GetFileNames(settingsFileName).Length == 0)
            {
                // File not exists. Let us NOT try to DeSerialize it.
                return;
            }

            // Read the stream from Isolated Storage.
            Stream stream = new IsolatedStorageFileStream(settingsFileName,
                        FileMode.OpenOrCreate, isoStore);
            if (stream != null)
            {
                try
                {
                    // DeSerialize the Hashtable from stream.
                    IFormatter formatter = new BinaryFormatter();
                    Hashtable appData = (Hashtable)formatter.Deserialize(stream);

                    // Enumerate through the collection and load our base Hashtable.
                    IDictionaryEnumerator enumerator = appData.GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        this[enumerator.Key] = enumerator.Value;
                    }
                }
                finally
                {
                    // We are done with it.
                    stream.Close();
                }
            }
        }

        public void ReLoad()
        {
            Load();
        }

        // Saves the configuration data to the persistent storage.
        public void Save()
        {
            // Open the stream from the IsolatedStorage.
            IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User
                        | IsolatedStorageScope.Assembly, null, null);
            Stream stream = new IsolatedStorageFileStream(settingsFileName,
                        FileMode.Create, isoStore);

            if (stream != null)
            {
                try
                {
                    // Serialize the Hashtable into the IsolatedStorage.
                    IFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(stream, (Hashtable)this);
                }
                finally
                {
                    stream.Close();
                }
            }
        }
    }
}
